import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
O grau de competição é calculado a partir da relação entre o número de componentes conexas e o total de vértices em um grafo. No contexto das licitações, cada vértice representa um CNPJ distinto e cada componente conexa representa um grupo de CNPJs relacionados considerando um dado vínculo (societário, endereço, telefone...).
Essa métrica permite um ordenamento parcial entre as licitações. Com isso, facilita-se a identificação daquelas onde há maior potencial de alguma forma de conluio.
Importando os dados utilizados na análise:
df = pd.read_pickle('../data/output/csv/grau_competicao')
dfv = df.drop(['cnpjs', 'vinculo_em_uso', 'grafo'], axis=1)
Ordenamos os dados de forma crescente fazendo com que as licitações com menor competitividade apareçam no topo dos resultados. No exemplo abaixo é possível visualizar 5 dessas licitações e informações associadas a cada uma.
dfv.sort_values(by=['grauCompeticao']).head(5)
| ano | municipio | modalidade | licitacao | valor | grauCompeticao | densidade | |
|---|---|---|---|---|---|---|---|
| 175822 | 2015 | Abaeté | Pregão Presencial | 985568 | 881100.0 | 0.250000 | 1.000000 |
| 223839 | 2018 | Juvenília | Pregão Presencial | 817707 | 826870.0 | 0.333333 | 0.666667 |
| 33570 | 2015 | Bom Despacho | Pregão Presencial | 718648 | 254985.4 | 0.333333 | 1.000000 |
| 176011 | 2018 | Abaeté | Pregão Presencial | 985703 | 268902.62 | 0.333333 | 1.000000 |
| 142000 | 2015 | Santana do Jacaré | Convite | 904182 | 29686.95 | 0.333333 | 0.666667 |
Podemos visualizar então, por exemplo, o grafo da licitação 985568, aquela com menor grau de competição. Observando o grafo gerado, verifica-se que todos os participantes dessa licitação estão relacionados entre si.
plt.figure(figsize=(10, 5))
nx.draw(df.iloc[175822]['grafo'], with_labels=True)
plt.title("Grafo da licitação 175822")
plt.draw()
Repetimos o procedimento acima, agora para a identificação das licitações com maior grau de competição. Abaixo, verifica-se que o grau de competição com valor 1 (total) está associado a uma densidade nula, ou seja, não há qualquer conexão entre os cnpjs participantes.
dfv.sort_values(by=['grauCompeticao'], ascending=False).head(5)
| ano | municipio | modalidade | licitacao | valor | grauCompeticao | densidade | |
|---|---|---|---|---|---|---|---|
| 0 | 2015 | Cascalho Rico | Pregão Presencial | 746396 | 1190070.0 | 1.0 | 0.0 |
| 172536 | 2017 | Carmo do Paranaíba | Pregão Presencial | 743854 | 16960.0 | 1.0 | 0.0 |
| 172522 | 2016 | Carmo do Paranaíba | Pregão Presencial | 743846 | 99763.527 | 1.0 | 0.0 |
| 172523 | 2016 | Carmo do Paranaíba | Pregão Presencial | 743847 | 41582.0 | 1.0 | 0.0 |
| 172524 | 2016 | Carmo do Paranaíba | Pregão Presencial | 743848 | 6382.0 | 1.0 | 0.0 |
Podemos visualizar qualquer uma dessas licitações. Selecionamos, por exemplo, a licitação 743846. É possível verificar que não há qualquer conexão, representada por uma linha entre os pontos, entre os cnpjs participantes.
plt.figure(figsize=(10, 5))
nx.draw(df.iloc[172522]['grafo'], with_labels=True)
plt.title("Grafo da licitação 743846")
plt.draw()
import plotly.express as px
fig = px.histogram(df, x='grauCompeticao', log_y=True, nbins=5,
title="Número de licitações por grau de competição",
labels={
'grauCompeticao' : "grau de competição"
}
)
fig.update_xaxes(visible=True, showticklabels=True)
fig.update_yaxes(title='número de licitacoes')
fig.show()